#pragma once

#include <memory>
#include <vector>

#include "abstract.hpp"
#include "fields.hpp"
#include "log.hpp"
#include "json.hpp"

namespace JsonMuduoRPC
{
    using Address = std::pair<std::string, uint16_t>;

    // JsonMessage包含一个JSON格式的消息
    class JsonMessage : public BaseMessage
    {
    public:
        using ptr = std::shared_ptr<JsonMessage>;

        virtual bool serialize(std::string &body) override
        {
            bool ret = JSON::serialize(_root, body);
            if (ret == false)
            {
                LOG(ERROR, "serialize failed!!");
                return false;
            }
            return true;
        }
        virtual bool unSerialize(const std::string &body) override
        {
            bool ret = JSON::unserialize(body, _root);
            if (ret == false)
            {
                LOG(ERROR, "unSerialize failed!!");
                return false;
            }
            return true;
        }

    protected:
        Json::Value _root;
    };

    class JsonRequest : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonRequest>;
    };

    // RPC请求包含
    // 请求方法——string 参数——JSON对象
    class RPCRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<RPCRequest>;

        virtual bool cheak() override
        {
            if (_root[KEY_METHOD].isNull() == true || _root[KEY_METHOD].isString() == false)
            {
                LOG(ERROR, "RPC方法字段不存在或者类型不正确");
                return false;
            }
            if (_root[KEY_PARAMS].isNull() == true || _root[KEY_PARAMS].isObject() == false)
            {
                LOG(ERROR, "RPC参数字段不存在或者类型不正确");
                return false;
            }

            return true;
        }

        const std::string getMethod() { return _root[KEY_METHOD].asString(); }
        const Json::Value getParams() { return _root[KEY_PARAMS]; }
        void setMethod(const std::string &method) { _root[KEY_METHOD] = method; }
        void setParams(const Json::Value params) { _root[KEY_PARAMS] = params; }
    };

    // 主题请求包含：
    // 主题名称——string 主题操作——TopicOpType
    // 如果主题操作位publish，那么还有一个消息——string
    class TopicRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<TopicRequest>;
        virtual bool cheak() override
        {
            if (_root[KEY_TOPIC_KEY].isNull() == true || _root[KEY_TOPIC_KEY].isString() == false)
            {
                LOG(ERROR, "主题字段不存在或者类型不正确");
                return false;
            }
            if (_root[KEY_OPTYPE].isNull() == true || _root[KEY_OPTYPE].isIntegral() == false)
            {
                LOG(ERROR, "主题操作字段不存在或者类型不正确");
                return false;
            }
            if (_root[KEY_OPTYPE].asInt() == (int)TopicOpType::TOPIC_PUBLISH &&
                (_root[KEY_TOPIC_MSG].isNull() == true || _root[KEY_TOPIC_MSG].isString() == false))
            {
                LOG(ERROR, "主题消息发布请求中没有消息内容字段或消息内容类型错误！");
                return false;
            }

            return true;
        }

        const std::string getTopic() { return _root[KEY_TOPIC_KEY].asString(); }
        const TopicOpType getOpType() { return (TopicOpType)_root[KEY_OPTYPE].asInt(); }
        const std::string getMessage() { return _root[KEY_TOPIC_MSG].asString(); }
        void setTopic(const std::string &topic) { _root[KEY_TOPIC_KEY] = topic; }
        void setOpType(const TopicOpType op_type) { _root[KEY_OPTYPE] = (int)op_type; }
        void setMessage(const std::string &message) { _root[KEY_TOPIC_MSG] = message; }
    };

    // 服务请求包含
    // 请求方法——string，请求操作——ServiceOpType
    // 如果请求操作不为服务发现SERVICE_DISCOVERY，那么还有主机地址host
    class ServiceRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<ServiceRequest>;
        virtual bool cheak() override
        {
            if (_root[KEY_METHOD].isNull() == true || _root[KEY_METHOD].isString() == false)
            {
                LOG(ERROR, "服务方法字段不存在或者类型不正确");
                return false;
            }
            if (_root[KEY_OPTYPE] != (int)ServiceOpType::SERVICE_DISCOVERY &&
                (_root[KEY_HOST].isNull() == true || _root[KEY_HOST].isObject() == false ||
                 _root[KEY_HOST][KEY_HOST_IP].isNull() == true || _root[KEY_HOST][KEY_HOST_IP].isString() == false ||
                 _root[KEY_HOST][KEY_HOST_PORT].isNull() == true || _root[KEY_HOST][KEY_HOST_PORT].isUInt() == false))
            {
                LOG(ERROR, "服务请求中主机地址信息错误！");
                return false;
            }
            if (_root[KEY_OPTYPE].isNull() == true || _root[KEY_OPTYPE].isIntegral() == false)
            {
                LOG(ERROR, "服务操作字段不存在或者类型不正确");
                return false;
            }

            return true;
        }

        const std::string getMethod() { return _root[KEY_METHOD].asString(); }
        const ServiceOpType getOpType() { return (ServiceOpType)_root[KEY_OPTYPE].asInt(); }
        const Address getHost()
        {
            Address add;
            add.first = _root[KEY_HOST][KEY_HOST_IP].asString();
            add.second = _root[KEY_HOST][KEY_HOST_PORT].asUInt();

            return add;
        }
        void setMethod(const std::string &topic) { _root[KEY_METHOD] = topic; }
        void setOpType(const ServiceOpType op_type) { _root[KEY_OPTYPE] = (int)op_type; }
        void setHost(const Address &add)
        {
            Json::Value host;
            host[KEY_HOST_IP] = add.first;
            host[KEY_HOST_PORT] = add.second;
            _root[KEY_HOST] = host;
        }
    };

    class JSONResponse : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JSONResponse>;

        // 在响应中，大部分的响应都只有响应状态码
        // 因此只需要判断响应状态码字段是否存在，类型是否正确即可
        virtual bool cheak() override
        {
            if (_root[KEY_RCODE].isNull() == true || _root[KEY_RCODE].isInt() == false)
            {
                LOG(ERROR, "响应RCODE不存在或者类型不正确！！");
                return false;
            }
            return true;
        }
        virtual void setRCode(const RCode& rCode) { _root[KEY_RCODE] = (int)rCode; }
        virtual RCode getRCode() { return (RCode)(_root[KEY_RCODE].asInt()); }
    };

    class RPCResponse : public JSONResponse
    {
    public:
        using ptr = std::shared_ptr<RPCResponse>;

        virtual bool cheak() override
        {
            if (_root[KEY_RCODE].isNull() == true || _root[KEY_RCODE].isInt() == false)
            {
                LOG(ERROR, "响应RCODE不存在或者类型不正确！！");
                return false;
            }
            if (_root[KEY_RESULT].isNull() == true)
            {
                LOG(ERROR, "响应结果不存在！！");
                return false;
            }

            return true;
        }

        Json::Value getResult() { return _root[KEY_RESULT]; }
        void setResult(const Json::Value &result) { _root[KEY_RESULT] = result; }
    };

    class TopicResponse : public JSONResponse
    {
    public:
        using ptr = std::shared_ptr<TopicResponse>;
    };

    class ServiceResponse : public JSONResponse
    {
    public:
        using ptr = std::shared_ptr<ServiceResponse>;

        virtual bool cheak() override
        {
            if (_root[KEY_RCODE].isNull() == true || _root[KEY_RCODE].isInt() == false)
            {
                LOG(ERROR, "响应RCODE不存在或者类型不正确");
                return false;
            }
            if (_root[KEY_OPTYPE].isNull() == true || _root[KEY_OPTYPE].isIntegral() == false)
            {
                LOG(ERROR, "服务操作字段不存在或者类型不正确");
                return false;
            }
            if (_root[KEY_OPTYPE].asInt() == (int)ServiceOpType::SERVICE_DISCOVERY)
            {
                if (_root[KEY_METHOD].isNull() == true || _root[KEY_METHOD].isString() == false)
                {
                    LOG(ERROR, "服务方法字段不存在或者类型不正确");
                    return false;
                }
                if (_root[KEY_HOST].isNull() == true || _root[KEY_HOST].isArray() == false)
                {
                    LOG(ERROR, "服务主机字段不存在或者类型不正确");
                    return false;
                }
            }

            return true;
        }

        ServiceOpType getOpType() { return (ServiceOpType)_root[KEY_OPTYPE].asInt(); }
        std::string getMethod() { return _root[KEY_METHOD].asString(); }
        std::vector<Address> getHosts()
        {
            std::vector<Address> ret;
            size_t sz = _root[KEY_HOST].size();
            for (int i = 0; i < sz; i++)
            {
                Address add;
                add.first = _root[KEY_HOST][i][KEY_HOST_IP].asString();
                add.second = _root[KEY_HOST][i][KEY_HOST_PORT].asUInt();
                ret.push_back(add);
            }

            return ret;
        }

        void setOpType(const ServiceOpType &op) { _root[KEY_OPTYPE] = (int)op; }
        void setMethod(const std::string &method) { _root[KEY_METHOD] = method; }
        void setHosts(const std::vector<Address> &hosts)
        {
            for (int i = 0; i < hosts.size(); i++)
            {
                Json::Value val;
                val[KEY_HOST_IP] = hosts[i].first;
                val[KEY_HOST_PORT] = hosts[i].second;
                _root[KEY_HOST].append(val);
            }
        }
    };

    // 实现一个消息对象的生产工厂
    class MessageFactory
    {
    public:
        static BaseMessage::ptr create(MType mType)
        {
            switch (mType)
            {
            case MType::REQ_RPC:
                return std::make_shared<RPCRequest>();
            case MType::RSP_RPC:
                return std::make_shared<RPCResponse>();
            case MType::REQ_TOPIC:
                return std::make_shared<TopicRequest>();
            case MType::RSP_TOPIC:
                return std::make_shared<TopicResponse>();
            case MType::REQ_SERVICE:
                return std::make_shared<ServiceRequest>();
            case MType::RSP_SERVICE:
                return std::make_shared<ServiceResponse>();
            default:
                return BaseMessage::ptr();
            }
        }

        template <typename T, typename... Args>
        static std::shared_ptr<T> create(Args &&...args)
        {
            return std::make_shared<T>(std::forward(args)...);
        }
    };
} // namespace JsonMuduoRPC
